/**
  ******************************************************************************
  * @file    common_func.c
  * @author  Sherlock
  * @version V0.1
  * @date    08/7/2024
  * @brief   Some common functions to be reused.
  ******************************************************************************
  * @copy
  *
  * <h2><center>&copy; COPYRIGHT 2010 Feirui</center></h2>
  */ 



/**
  * @brief  INCLUDE FILES.
  */
#ifndef	COMMON_FUNC_GLOBALS
#define	COMMON_FUNC_GLOBALS
#include <includes.h>

// 局部变量
static const uint16_t crc16_table[16] = {0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401, 0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400}; //CRC短表


/**
 * @brief 字符串查找
 * @param str 原始字符串
 * @param substring 查找字符串
 * @param len 查找长度限制
 * @return RET_FINDSUB 
 */
RET_FINDSUB Comm_StrStr(char *str, const char *substring, size_t len)
{
    RET_FINDSUB ret_findSub = {NULL, NULL};
    size_t sub_len = strlen(substring);

    if (sub_len == 0)
    {
        ret_findSub.adr = str;
        ret_findSub.index = 0;
        return ret_findSub;
    }
    else if (sub_len > len)
    {
        // 如果子字符串比指定长度长，直接返回null
        return ret_findSub;
    }
    // 在str中的前len个字符中查找substring
    for (size_t i = 0; i <= len - sub_len; i++)
    {
        if (strncmp(&str[i], substring, sub_len) == 0)
        {
            ret_findSub.adr = &str[i];
            ret_findSub.index = i;
            return ret_findSub; // 找到字符串，返回其起始位置
        }
    }
    return ret_findSub; // 未找到字符串
}

/**
 * @brief 整型转字符串
 * @param Buffer 目标缓冲区
 * @param Data 数据源
 * @param NumLimit 数据长度
 */
void Comm_IntegerToString(uint8_t *Buffer, uint32_t Data, uint8_t NumLimit){
    if (NumLimit == 0)
        return;
    
    Buffer += NumLimit - 1;
    for (uint8_t i = 0; i < NumLimit; i++){
        *(Buffer--) = (Data % 10) + '0';
        Data /= 10;
    }
}

/**
 * @brief 字符串比较
 * @param source 比较源
 * @param target 比较目标
 * @param Limit 比较长度
 * @return uint8_t 1相同  0不同
 */
uint8_t Comm_CompareFixedString(uint8_t *source, uint8_t *target, uint16_t Limit)
{
    for (; Limit > 0 && *target != '\0'; Limit--, source++, target++)
        if (*source != *target)
            return (DEF_FALSE);
    return (DEF_TRUE);
}

/**
 * @brief 计算校验和
 * @param Source 数据源
 * @param Number 数据长度
 * @return uint16_t 校验和
 */
uint16_t Comm_CalCheckSum(uint8_t *Source, uint16_t Number)
{
    uint16_t Sum = 0;
    for (uint16_t i = 0; i < Number; i++, Source++)
        Sum += *Source;

    return (Sum);
}

/**
 * @brief 大小端数据转换
 * @param mode 0小端转大端， 1大端转小端
 * @param sourData 数据源
 * @param destData 数据目标
 * @param convertLen 转换长度
 */
void Comm_LittleBigEndian_Convert(uint8_t mode, uint8_t *sourData, uint8_t *destData, uint8_t convertLen){
    uint8_t i = 0;
    uint8_t *sourPoint = (uint8_t *)sourData;
    uint8_t *destPoint = (uint8_t *)destData;

    if(mode == 0){
        for(i = 0; i < convertLen; i++){
            destPoint[i] = sourPoint[convertLen - 1 - i];
        }
    }
    else if(mode == 1){
        for(i = 0; i < convertLen; i++){
            destPoint[convertLen - 1 - i] = sourPoint[i];
        }
    }
}

/**
 * @brief 计算CRC16校验和
 * @param data 需要检验的数据
 * @param length 检验长度
 * @return uint16_t CRC16检验和
 */
uint16_t Comm_CalCRC16(uint8_t * data, uint16_t length){
    uint8_t ch = 0;
    uint16_t i = 0;
    uint16_t crc = 0xFFFF;

    for (i = 0; i < length; i++){
        ch = data[i];
        crc = (uint16_t)(crc16_table[(ch ^ crc) & 0x0F] ^ (crc >> 4));
        crc = (uint16_t)(crc16_table[((ch >> 4) ^ crc) & 0x0F] ^ (crc >> 4));
    }
    crc = (uint16_t)((crc & 0xFF) << 8 | (crc >> 8));
    return crc;
}


/**
  * @brief  ADC ExciteVolt calculation
  * @param  filterCoefficient 滤波系数，必须是0-1的小数
  * @return none.
  */
float Cal_1OrdLowPassFilter(float *lastValue, uint16_t *StartAddr, uint8_t AddrInterval, uint8_t Number, float filterCoefficient)
{
	float CalTemp = *lastValue;
	
	for(uint8_t i=0; i<Number; i++)
	{
		CalTemp = CalTemp*(1-filterCoefficient) + ((float)*StartAddr-0)*filterCoefficient;//2048
		StartAddr += AddrInterval;
	}
	
	*lastValue=CalTemp;
	return(CalTemp);
}


/* CRC Calculation */
uint16_t CalBufferDataCRC161(uint8_t *ptr, uint16_t len)
{
	uint8_t  i;
	uint16_t crc=0xffff;
  
	while(len--!=0) 
	{
		crc ^= *ptr++;
    
		for(i=0;i<8;i++) 
		{
			if(crc&1)
		 	{
				crc >>= 1;
				crc ^= 0xa001;
			}
			else 
				crc >>= 1;
		}
	}
	
	return(crc);
}


/* 缓冲数据复制 */
void Comm_CopyOriginToDestBuffer(uint16_t *originAddr, uint16_t *destAddr, uint8_t copyNum)
{
	for(; copyNum>0; copyNum--)
	{
		*destAddr = *originAddr;
		destAddr++;
		originAddr++;
	}
}


/*****************************************************************************************************************
 *                                                  中值滤波
 *******************************************************************************************************************/
/* 中位数滤波初始化 */
void Comm_MediumFilterInitStructure(MediumFilterObjTypeDef *MediumFilterStruct)
{
  MediumFilterStruct->currIndex = 0;
  for(uint8_t i=0; i<MediumFilterLenMax; i++)
    MediumFilterStruct->FilterArr[i] = 0;
}

/* 中位数滤波输入新值 */
void Comm_MediumFilterInput(MediumFilterObjTypeDef *MediumFilterStruct, float newMember)
{
  MediumFilterStruct->FilterArr[MediumFilterStruct->currIndex] = newMember;
  MediumFilterStruct->currIndex = (MediumFilterStruct->currIndex + 1) % MediumFilterLenMax;
}

/* 中位数滤波输入新值，并获取当前中位数 */
float Comm_MediumFilterInputAndGetValue(MediumFilterObjTypeDef *MediumFilterStruct, float newMember)
{
  Comm_MediumFilterInput(MediumFilterStruct, newMember);
  // 拷贝数组，避免修改原数组
  float copyArr[MediumFilterLenMax];
  for(uint8_t i=0; i<MediumFilterLenMax; i++)
    copyArr[i] = MediumFilterStruct->FilterArr[i];
  
  return GetMediumNum(copyArr, MediumFilterLenMax);
}

static void quickSort(float *arr, int left, int right);
static int partition(float *arr, int left, int right);

float GetMediumNum(float *arr, uint8_t size)
{
  // 使用快速排序对数组进行排序
  quickSort(arr, 0, size - 1);

  // 计算中值
  if (size % 2 == 1) {
      // 数组有奇数个元素，返回中间一个元素
      return (float)arr[size / 2];
  } else {
      // 数组有偶数个元素，返回中间两个元素平均值
      return (float)((arr[size / 2 - 1] + arr[size / 2]) / 2.0);
  }
}

static void quickSort(float *arr, int left, int right) {
  if (left < right) {
      int pivotIndex = partition(arr, left, right);
      quickSort(arr, left, pivotIndex - 1);
      quickSort(arr, pivotIndex + 1, right);
  }
}

static int partition(float *arr, int left, int right) {
  float pivot = arr[right];
  int i = left - 1;

  for (int j = left; j < right; j++) {
      if (arr[j] <= pivot) {
          i++;
          float temp = arr[i];
          arr[i] = arr[j];
          arr[j] = temp;
      }
  }
  float temp = arr[i + 1];
  arr[i + 1] = arr[right];
  arr[right] = temp;
  return i + 1;
}


/*****************************************************************************************************************
 *                                                  一阶惯性滤波
 *******************************************************************************************************************/
float Comm_LowPass1OrderGetValue(float newValue, float *lastValue, float lowPassFactor)
{
  float lowPassValue = newValue * lowPassFactor + *lastValue * (1-lowPassFactor);
  *lastValue = lowPassValue;
  return lowPassValue;
}


/*****************************************************************************************************************
 *                                                  告警逻辑处理
 *******************************************************************************************************************/
uint8_t InputsAlarmSmartHandling(InputAlarmSmart_ParamDef *Param)
{
	uint8_t  Status=DEF_FALSE;
	
	/********************************/
	/********************************/
	/* Disable Touch Alarm */
	if(Param->Option==DEF_FALSE)
	{
		if(Param->OffType==AlarmOperaType_DisableActive)
		{
			if(*(Param->Status)==DEF_FALSE)
				Status=DEF_TRUE;
			*(Param->Status)=DEF_TRUE;
			
			*(Param->Ticnt) =0;
			if(Param->Actcnt!=NULL)
				*(Param->Actcnt) =0;
		}
		else if(Param->OffType==AlarmOperaType_DisableInActive)
		{
			if(*(Param->Status)==DEF_TRUE)
				Status=DEF_TRUE;
			*(Param->Status)=DEF_FALSE;
			
			*(Param->Ticnt) =0;
			if(Param->Actcnt!=NULL)
				*(Param->Actcnt) =0;
		}
		
		return(Status);
	}
  /********************************/
	/********************************/
	/* Enable Touch Alarm */
	/*************/
	/* High Shut */
	if(Param->OperaType==AlarmOperaType_HighShut)
	{
		/* Has Alarm */
		if(*(Param->Status))
		{
			if((Param->Value)>=(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->LowTiLimit))
				{
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}
			
			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			{
			  (*(Param->Actcnt))++;
			  if(*(Param->Actcnt)>=(Param->ActLimit))
			  {
			  	*(Param->Actcnt) =0;
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
			  }
			}
		}
		/* No Alarm  */
		else
		{
			if((Param->Value)<(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->HighTiLimit))
				{
					*(Param->Status)=DEF_TRUE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}
			
			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			  *(Param->Actcnt) =0;
	  }
	}
		
	/*************/
	/* High Warn */
	else if(Param->OperaType==AlarmOperaType_HighWarn)
	{
		/* Has Alarm */
		if(*(Param->Status))
		{
			if((Param->Value)>(Param->Return))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->LowTiLimit))
				{
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			{
			  (*(Param->Actcnt))++;
			  if(*(Param->Actcnt)>=(Param->ActLimit))
			  {
			  	*(Param->Actcnt) =0;
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
			  }
			}
		}
		/* No Alarm  */
		else
		{
			if((Param->Value)<(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->HighTiLimit))
				{
					*(Param->Status)=DEF_TRUE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			  *(Param->Actcnt) =0;
	  }
	}

	/*************/
	/* Low Warn */
	else if(Param->OperaType==AlarmOperaType_LowWarn)
	{
		/* Has Alarm */
		if(*(Param->Status))
		{
			if((Param->Value)<(Param->Return))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->HighTiLimit))
				{
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			{
			  (*(Param->Actcnt))++;
			  if(*(Param->Actcnt)>=(Param->ActLimit))
			  {
			  	*(Param->Actcnt) =0;
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
			  }
			}
		}
		/* No Alarm  */
		else
		{
			if((Param->Value)>(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->LowTiLimit))
				{
					*(Param->Status)=DEF_TRUE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			  *(Param->Actcnt) =0;
	  }
	}

	/*************/
	/* Low Shut */
	else if(Param->OperaType==AlarmOperaType_LowShut)
	{
		/* Has Alarm */
		if(*(Param->Status))
		{
			if((Param->Value)<=(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->HighTiLimit))
				{
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			{
			  (*(Param->Actcnt))++;
			  if(*(Param->Actcnt)>=(Param->ActLimit))
			  {
			  	*(Param->Actcnt) =0;
					*(Param->Status)=DEF_FALSE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
			  }
			}
		}
		/* No Alarm  */
		else
		{
			if((Param->Value)>(Param->Trip))
				*(Param->Ticnt) =0;
			else
			{
				(*(Param->Ticnt))++;
				if(*(Param->Ticnt)>=(Param->LowTiLimit))
				{
					*(Param->Status)=DEF_TRUE;
					*(Param->Ticnt) =0;
					Status=DEF_TRUE;
				}
			}

			/* Max Alarm period */
			if(Param->Actcnt!=NULL)
			  *(Param->Actcnt) =0;
	  }
	}
	
	return(Status);
}


#endif	/*	COMMON_FUNC_GLOBALS	*/

/******************* (C) COPYRIGHT 2010 Feirui *****END OF FILE****/
